/* 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <QMenu>
#include <QMessageBox>
#include <QTreeWidgetItem>
#include <QtCore>
#include <QFileDialog>
#include <QFuture>
#include "imagemanager.h"
#include "imagestorage.h"
#include "log.h"
#include "mainwindow.h"
#include "ui_imagemanager.h"


extern Wishmaster::ImageStorage* g_imagestorage;

class TagListItem : public QTreeWidgetItem
{
	static const int MyType = UserType + 1;
	int m_picNumber;
public:
	TagListItem(QTreeWidget* parent, int picnum) : QTreeWidgetItem(parent, MyType), m_picNumber(picnum) {}

	bool operator<(const QTreeWidgetItem& other) const
	{
		if(other.type() == MyType)
		{
			return (m_picNumber < ((const TagListItem&)other).m_picNumber);
		}
		return false;
	}
};

class PicListItem : public QListWidgetItem
{
	static const int MyType = UserType + 2;
	int m_index;
public:
	PicListItem(int index) : QListWidgetItem(0, MyType), m_index(index) {}

	bool operator<(const QListWidgetItem& other) const
	{
		if(other.type() == MyType)
		{
			return m_index < (static_cast<const PicListItem&>(other)).m_index;
		}
		return false;
	}
};

ImageManager::ImageManager(MainWindow* mainform, QWidget* widget) : QWidget(widget),
	m_ui(new Ui::ImageManager()), m_mainform(mainform), m_timerID(0), m_select(false), m_loadingThread(NULL),
	m_itemsInPage(100)
{
	m_ui->setupUi(this);
	m_ui->e_search->setText(tr("Enter tags here, delimited with spaces"));
	m_ui->e_search->setStyleSheet("color: #dddddd;");
	m_ui->e_search->installEventFilter(this);
	m_tagsEmpty = true;
	refreshTaglist();
	updatePageLine();

	connect(&m_imageFutureWatcher, SIGNAL(finished()), this, SLOT(imagesLoaded()));
	connect(&m_imageFutureWatcher, SIGNAL(progressValueChanged(int)), this, SLOT(imageLoadProgress(int)));
	connect(&m_imageFutureWatcher, SIGNAL(resultReadyAt(int)), this, SLOT(imageLoadingDone(int)));
}

ImageManager::~ImageManager()
{

}

void ImageManager::closeEvent(QCloseEvent* /*event*/)
{
	QSettings settings;
	settings.setValue("imagemanager/splitter_state", m_ui->splitter->saveGeometry());
	settings.setValue("imagemanager/taglist_column0_width", m_ui->tw_tags->columnWidth(0));
	settings.setValue("imagemanager/taglist_column1_width", m_ui->tw_tags->columnWidth(1));
}

static QImage scale(const Wishmaster::ImageDescriptor& desc)
{
	return QImage(desc.path).scaled(QSize(128, 128), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

void ImageManager::updateList()
{
	if(m_imageFuture.isRunning())
		m_imageFuture.cancel();
	m_ui->list_pics->clear();
	m_imageFuture = QtConcurrent::mapped(m_imageList.mid(m_currentPage * m_itemsInPage, m_itemsInPage), scale);
	m_imageFutureWatcher.setFuture(m_imageFuture);
}

void ImageManager::imagesLoaded()
{

}

void ImageManager::imageLoadingDone(int index)
{
	QImage img = m_imageFutureWatcher.resultAt(index);
	PicListItem* item = new PicListItem(index);
	item->setIcon(QPixmap::fromImage(img));
	item->setData(RoleId, m_imageList.at(index + m_currentPage * m_itemsInPage).id);
	item->setData(RolePicPath, m_imageList.at(index + m_currentPage * m_itemsInPage).path);
	for(int i = 0; i < m_ui->list_pics->count(); i++)
	{
		if(item < m_ui->list_pics->item(i))
		{
			m_ui->list_pics->insertItem(i, item);
			return;
		}
	}
	m_ui->list_pics->addItem(item);
}

void ImageManager::imageLoadProgress(int progress)
{
	m_ui->pb_loading->setValue(100. * progress / (m_imageFutureWatcher.progressMaximum() - m_imageFutureWatcher.progressMinimum()));
	if(progress == m_imageFutureWatcher.progressMaximum())
		m_ui->pb_loading->hide();
}

void ImageManager::startSearch()
{
	if(m_ui->e_search->text().isEmpty())
		return;

	m_ui->e_search->setStyleSheet("");
	m_ui->pb_loading->setVisible(true);
	m_ui->list_pics->setFocus();
	m_currentPage = 0;

	QStringList tags;
	if(!m_ui->e_search->text().isEmpty())
	{
		tags = m_ui->e_search->text().split(" ");
	}
	m_imageList = g_imagestorage->getImagesForTags(tags);
	m_currentPage = 0;
	m_maxPage = m_imageList.size() / m_itemsInPage;

	updateQueryLineEdit();
	updateList();
	updatePageLine();
}

void ImageManager::imageClicked(const QModelIndex& index)
{
	if(m_select)
		select();
	else
		viewImage();

}

void ImageManager::contextMenu(const QPoint& p)
{
	QList<QAction*> actions;
	if(m_ui->list_pics->indexAt(p).isValid())
	{
		if(m_select)
			actions.append(m_ui->actionSelect);
		else
			actions.append(m_ui->actionView);
		actions.append(m_ui->actionDelete_Image);
    }
	if(actions.count() > 0)
		QMenu::exec(actions, m_ui->list_pics->mapToGlobal(p));
}

void ImageManager::deleteImage()
{
	QListWidgetItem* item = m_ui->list_pics->currentItem();
	QString path = item->data(RolePicPath).toString();
	if(!path.isEmpty())
	{
		int image_id = g_imagestorage->getIDByPath(path);
		if(!g_imagestorage->deleteImage(image_id))
		{
			QMessageBox::warning(this, tr("Error"), tr("Unable to delete image"));
		}
	}
}

void ImageManager::setMode(bool select)
{
	m_select = select;
}

void ImageManager::select()
{
	QListWidgetItem* item = m_ui->list_pics->currentItem();
	emit pictureSelected(item->data(RolePicPath).toString());
	hide();
}

void ImageManager::viewImage()
{
	m_mainform->getImageView()->viewByID(m_ui->list_pics->currentItem()->data(RoleId).toUInt());
	m_mainform->getImageView()->show();
}

bool ImageManager::eventFilter(QObject* obj, QEvent* event)
{
	if(obj == m_ui->e_search)
	{
		if(event->type() == QEvent::FocusOut)
		{
			updateQueryLineEdit();
			return true;
		}
		else if(event->type() == QEvent::FocusIn)
		{
			if(m_tagsEmpty)
			{
				m_ui->e_search->setText("");
				m_ui->e_search->setStyleSheet("");
			}
		}
		return false;
	}
	return QWidget::eventFilter(obj, event);
}

void ImageManager::updateQueryLineEdit()
{
	if(m_ui->e_search->text().isEmpty())
	{
		m_ui->e_search->setText(tr("Enter tags here, delimited with spaces"));
		m_ui->e_search->setStyleSheet("color: #dddddd;");
		m_tagsEmpty = true;
	}
	else
	{
		m_ui->e_search->setStyleSheet("");
		m_tagsEmpty = false;
	}
}

void ImageManager::showEvent(QShowEvent* event)
{
	refreshTaglist();
	//m_ui->tw_tags->resizeColumnToContents(0);
	QSettings settings;
	m_ui->splitter->restoreState(settings.value("imagemanager/splitter_state").toByteArray());
	m_ui->tw_tags->setColumnWidth(0, settings.value("imagemanager/taglist_column0_width", 200).toInt());
	m_ui->tw_tags->setColumnWidth(1, settings.value("imagemanager/taglist_column0_width", 50).toInt());
}

void ImageManager::hideEvent(QHideEvent* event)
{
	QSettings settings;
	settings.setValue("imagemanager/splitter_state", m_ui->splitter->saveState());
}

bool ImageManager::event(QEvent* event)
{
	if(event->type() == QEvent::LanguageChange)
	{
		m_ui->retranslateUi(this);
		return true;
	}
	return QWidget::event(event);
}

void ImageManager::refreshTaglist()
{
	doRefreshTaglist();
	//QtConcurrent::run(this, &ImageManager::doRefreshTaglist);
}

void ImageManager::doRefreshTaglist()
{
	m_ui->tw_tags->clear();
	QList<TagInfo> tags = g_imagestorage->allTags();
	foreach(const TagInfo& tag, tags)
	{
		QTreeWidgetItem* item = new TagListItem(m_ui->tw_tags, tag.images);
		item->setText(0, QString("%1").arg(tag.tag));
		item->setText(1, QString::number(tag.images));
		item->setData(0, RoleTag, tag.tag);
	}
	m_ui->tw_tags->sortItems(1, Qt::DescendingOrder);
	log(llDebug, "tagList refreshed");
}

void ImageManager::tagClicked(QTreeWidgetItem* item, int /*column*/)
{
	QString currentQuery = m_ui->e_search->text();
	if(m_tagsEmpty)
	{
		m_tagsEmpty = false;
		currentQuery = "";
	}
	QString tag = item->data(0, RoleTag).toString();
	if(QApplication::keyboardModifiers() & Qt::ShiftModifier)
	{
		if(currentQuery.contains(tag))
			return;
		if(!currentQuery.endsWith(' ') && !currentQuery.isEmpty())
			currentQuery.append(' ');
		currentQuery.append(tag);
	}
	else
		currentQuery = tag;
	m_ui->e_search->setText(currentQuery);

	startSearch();
	updatePageLine();
}

void ImageManager::clearQuery()
{
	m_ui->e_search->setText("");
	updateQueryLineEdit();
	updatePageLine();
	m_ui->list_pics->clear();
	m_imageList.clear();
	m_images.clear();
}

void ImageManager::updatePageLine()
{
	if(m_tagsEmpty)
		m_ui->gb_page->hide();
	else
	{
		m_ui->gb_page->show();
		m_ui->e_currentPage->setText(QString::number(m_currentPage + 1));
		m_ui->b_prevPage->setEnabled(m_currentPage != 0);
		m_ui->b_nextPage->setEnabled(m_currentPage != m_maxPage);
		m_ui->l_maxPage->setText(QString::number(m_maxPage + 1));
	}
}

void ImageManager::prevPage()
{
	if(m_currentPage > 0)
		m_currentPage--;
	updatePageLine();
	updateList();
}

void ImageManager::nextPage()
{
	if(m_currentPage < m_maxPage)
		m_currentPage++;
	updatePageLine();
	updateList();
}

void ImageManager::exportImages()
{
	if(m_tagsEmpty)
		return;
	QString basename = m_ui->e_search->text();
	basename.replace(' ', '_');
	QString path = QFileDialog::getExistingDirectory(this, tr("Export images..."));
	if(path.isEmpty())
		return;

	int num = 0;
	foreach(const Wishmaster::ImageDescriptor& img, m_imageList)
	{
		QFile f(img.path);
		QFileInfo info(f);
		f.copy(path + QDir::separator() + basename + QString::number(num).rightJustified(5, '0', false) + "." + info.completeSuffix());
		num++;
	}
}


void ImageManager::pageNumberChanged(const QString& newstring)
{
	bool ok;
	int newPage = newstring.toUInt(&ok);
	if(!ok)
		return;
	if(m_currentPage == newPage - 1)
		return;

	if((newPage < 0) || (newPage >= m_maxPage))
		return;

	m_currentPage = newPage - 1;
	updateList();
}
